package practica1.domain;

import java.io.File;
import java.util.ArrayList;
import practica1.util.HashCodeUtil;

/**
 * Clase que implementa el modelo de un experimento
 * @author Miguel González - Ceura
 */
public class Experimento {
    //Escuchadores de nuestro modelo
    private ArrayList<ExperimentoListener> expListener;
    
    //Objetos del modelo
    protected File fichExperimento;
    protected String nombreExperimento;
    protected String tipoBacteria;
    protected String nombreInvestigador;
    protected String proyectoInvestigacion;
    protected int numDiasExperimento;
    protected int limiteAlimentacionMaxima;
    protected String unidadesMedida;
    
    /**
     * Constructor sobrecargado del experimento donde recibe todos los parámetros
     * @param fichExperimento Fichero donde se encuentra el experimento
     * @param nombreExperimento Nombre del experimento
     * @param tipoBacteria Tipo de bacteria del experimento
     * @param nombreInvestigador Nombre del investigador del experimento
     * @param proyectoInvestigacion Proyecto de investigación del experimento
     */
    public Experimento(File fichExperimento, String nombreExperimento,
            String tipoBacteria, String nombreInvestigador,
            String proyectoInvestigacion, int numDiasExperimento,
            int limiteAlimentacionMaxima, String unidadesMedida) {
        //Instanciamos los escuchadores de nuestro modelo
        expListener = new ArrayList<ExperimentoListener>();
        
        //Instanciamos los objetos del modelo
        this.fichExperimento = fichExperimento;
        this.nombreExperimento = nombreExperimento;
        this.tipoBacteria = tipoBacteria;
        this.nombreInvestigador = nombreInvestigador;
        this.proyectoInvestigacion = proyectoInvestigacion;
        this.numDiasExperimento = numDiasExperimento;
        this.limiteAlimentacionMaxima = limiteAlimentacionMaxima;
        this.unidadesMedida = unidadesMedida;
    }

    /**
     * Devuelve el nombre del experimento
     * @return String nombreExperimento
     */
    @Override
    public String toString() {
        return nombreExperimento;
    }
    
    /**
     * Método que compara un objeto con el experimento
     * @param experimento Object Experimento a comparar
     * @return Devuelve verdad si el objeto es un experimento igual,
     * sino falso
     */
    @Override
    public boolean equals(Object experimento) {
        if(experimento instanceof Experimento) {
            Experimento ex = (Experimento) experimento;

            if(ex.getFichExperimento().equals(fichExperimento) &&
                    ex.getNombreExperimento().equals(nombreExperimento) &&
                    ex.getTipoBacteria().equals(tipoBacteria) &&
                    ex.getNombreInvestigador().equals(nombreInvestigador) &&
                    ex.getProyectoInvestigacion().equals(proyectoInvestigacion)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Devuelve el hashCode del experimento
     * @return int hashCode
     */
    @Override
    public int hashCode() {
        int result = HashCodeUtil.SEED;
        
        result = HashCodeUtil.hash(result, fichExperimento);
        result = HashCodeUtil.hash(result, nombreExperimento);
        result = HashCodeUtil.hash(result, tipoBacteria); 
        result = HashCodeUtil.hash(result, nombreInvestigador);
        result = HashCodeUtil.hash(result, proyectoInvestigacion);
        
        return result;
    }
    
    @Override
    public Experimento clone() {
        Experimento exp = new Experimento(fichExperimento, nombreExperimento, 
                tipoBacteria, nombreInvestigador, proyectoInvestigacion, 
                numDiasExperimento, limiteAlimentacionMaxima, unidadesMedida);
        
        return exp;
    }
    
    /**
     * Permite suscribirse a los cambios en el experimento
     * @param modeloExperimentoListener ExperimentoListener
     */
    public void addExperimentoListener(ExperimentoListener
            modeloExperimentoListener) {
        expListener.add(modeloExperimentoListener);
    }

    /**
     * Permite desuscribirse a los cambios en el experimento
     * @param modeloExperimentoListener ExperimentoListener
     */
    public void removeExperimentoListener(ExperimentoListener
            modeloExperimentoListener) {
        expListener.remove(modeloExperimentoListener);
    }

    /**
     * @return Devuelve el fichero del experimento
     */
    public File getFichExperimento() {
        return fichExperimento;
    }
    
    /**
     * Establece el nuevo fichero del experimento
     * @param fichExperimento File
     */
    public void setFichExperimento(File fichExperimento) {
        this.fichExperimento = fichExperimento;
        fireExperimentoChange();
    }

    /**
     * @return Devuelve el nombre del experimento
     */
    public String getNombreExperimento() {
        return nombreExperimento;
    }
    
    /**
     * Establece el nombre del experimento
     * @param nombreExperimento Devuelve el nombre del experimento
     */
    public void setNombreExperimento(String nombreExperimento) {
        this.nombreExperimento = nombreExperimento;
        fireExperimentoChange();
    }

    /**
     * Devuelve el tipo de bacteria del experimento
     * @return String tipoBacteria
     */
    public String getTipoBacteria() {
        return tipoBacteria;
    }

    /**
     * Establece el nuevo tipo de bacteria del experimento
     * @param tipoBacteria String
     */
    public void setTipoBacteria(String tipoBacteria) {
        this.tipoBacteria = tipoBacteria;
        fireExperimentoChange();
    }
    
    /**
     * Establece e nuevo nombre del investigador
     * @param nombreInvestigador String
     */
    public void setNombreInvestigador(String nombreInvestigador) {
        this.nombreInvestigador = nombreInvestigador;
        fireExperimentoChange();
    }
    
    /**
     * Devuelve el nombre del investigador del experimento
     * @return String nombreInvestigador
     */
    public String getNombreInvestigador() {
        return nombreInvestigador;
    }
    
    /**
     * Establece el nuevo proyecto de investigación del experimento
     * @param proyectoInvestigacion String
     */
    public void setProyectoInvestigacion(String proyectoInvestigacion) {
        this.proyectoInvestigacion = proyectoInvestigacion;
        fireExperimentoChange();
    }
    
    /**
     * Devuelve el proyecto de investigación del experimento
     * @return String proyectoInvestigacion
     */
    public String getProyectoInvestigacion() {
        return proyectoInvestigacion;
    }
    
    /**
     * Lanza el evento a todos los escuchadores de que el experimento ha cambiado
     */
    private void fireExperimentoChange() {
        for(ExperimentoListener l : expListener) {
            l.modificadoExperimento(new ExperimentoEvent(this));
        }
    }

    /**
     * @return the numDiasExperimento
     */
    public int getNumDiasExperimento() {
        return numDiasExperimento;
    }

    /**
     * @param numDiasExperimento the numDiasExperimento to set
     */
    public void setNumDiasExperimento(int numDiasExperimento) {
        this.numDiasExperimento = numDiasExperimento;
        fireExperimentoChange();
    }

    /**
     * @return the limiteAlimentacionMaxima
     */
    public int getLimiteAlimentacionMaxima() {
        return limiteAlimentacionMaxima;
    }

    /**
     * @param limiteAlimentacionMaxima the limiteAlimentacionMaxima to set
     */
    public void setLimiteAlimentacionMaxima(int limiteAlimentacionMaxima) {
        this.limiteAlimentacionMaxima = limiteAlimentacionMaxima;
        fireExperimentoChange();
    }

    /**
     * @return the unidadesMedida
     */
    public String getUnidadesMedida() {
        return unidadesMedida;
    }

    /**
     * @param unidadesMedida the unidadesMedida to set
     */
    public void setUnidadesMedida(String unidadesMedida) {
        this.unidadesMedida = unidadesMedida;
        fireExperimentoChange();
    }
}
